package com.leizhi.demo.monitor.achieve;

import gov.nist.core.InternalErrorHandler;
import gov.nist.javax.sip.clientauthutils.DigestServerAuthenticationHelper;

import javax.sip.address.URI;
import javax.sip.header.AuthorizationHeader;
import javax.sip.header.HeaderFactory;
import javax.sip.header.ProxyAuthenticateHeader;
import javax.sip.message.Request;
import javax.sip.message.Response;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Date;
import java.util.Random;

/**
 * @Description 重写 gov.nist.javax.sip.clientauthutils.DigestServerAuthenticationHelper 类
 * 因为该类在 doAuthenticatePlainTextPassword 方法中使用的是 Proxy-Authorization 导致获取不到 Authorization 头部信息
 * @Version 1.0.0-SNAPSHOT
 * @Author leizhi
 * @Date 2025/4/28 11:23
 */
public class AuthenticationHelper {
    private final MessageDigest messageDigest = MessageDigest.getInstance("MD5");
    private final DigestServerAuthenticationHelper authenticationHelper = new DigestServerAuthenticationHelper();

    private static final char[] toHex = new char[]{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};

    public AuthenticationHelper() throws NoSuchAlgorithmException {
    }

    public static String toHexString(byte[] b) {
        int pos = 0;
        char[] c = new char[b.length * 2];
        for (byte value : b) {
            c[pos++] = toHex[value >> 4 & 15];
            c[pos++] = toHex[value & 15];
        }

        return new String(c);
    }

    private String generateNonce() {
        Date date = new Date();
        long time = date.getTime();
        Random rand = new Random();
        long pad = rand.nextLong();
        String nonceString = time + Long.toString(pad);
        byte[] mdBytes = this.messageDigest.digest(nonceString.getBytes());
        return toHexString(mdBytes);
    }

    public void generateChallenge(HeaderFactory headerFactory, Response response, String realm) {
        try {
            ProxyAuthenticateHeader proxyAuthenticate = headerFactory.createProxyAuthenticateHeader("Digest");
            proxyAuthenticate.setParameter("realm", realm);
            proxyAuthenticate.setParameter("nonce", this.generateNonce());
            proxyAuthenticate.setParameter("opaque", "");
            proxyAuthenticate.setParameter("stale", "FALSE");
            proxyAuthenticate.setParameter("algorithm", "MD5");
            response.setHeader(proxyAuthenticate);
        } catch (Exception var5) {
            InternalErrorHandler.handleException(var5);
        }

    }

    public boolean doAuthenticate(Request request, String pass) {
        AuthorizationHeader authHeader = (AuthorizationHeader) request.getHeader(AuthorizationHeader.NAME);
        if (authHeader == null) {
            return authenticationHelper.doAuthenticatePlainTextPassword(request, pass);
        } else {
            String realm = authHeader.getRealm();
            String username = authHeader.getUsername();
            if (username != null && realm != null) {
                String nonce = authHeader.getNonce();
                URI uri = authHeader.getURI();
                if (uri == null) {
                    return false;
                } else {
                    String A1 = username + ":" + realm + ":" + pass;
                    String A2 = request.getMethod().toUpperCase() + ":" + uri.toString();
                    byte[] mdbytes = this.messageDigest.digest(A1.getBytes());
                    String HA1 = toHexString(mdbytes);
                    mdbytes = this.messageDigest.digest(A2.getBytes());
                    String HA2 = toHexString(mdbytes);
                    String cNonce = authHeader.getCNonce();
                    String KD = HA1 + ":" + nonce;
                    if (cNonce != null) {
                        KD = KD + ":" + cNonce;
                    }

                    KD = KD + ":" + HA2;
                    mdbytes = this.messageDigest.digest(KD.getBytes());
                    String mdString = toHexString(mdbytes);
                    String response = authHeader.getResponse();
                    return mdString.equals(response);
                }
            } else {
                return false;
            }
        }
    }
}
